package com.iflytek.uoamp.notify.core.dump;

import java.io.File;
import java.text.MessageFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import java.util.TimerTask;

import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;

import com.iflytek.uoamp.common.notify.constant.ConfigName;
import com.iflytek.uoamp.common.notify.constant.ConstField;
import com.iflytek.uoamp.common.notify.enumerate.Type;
import com.iflytek.uoamp.common.notify.exception.NotifyException;
import com.iflytek.uoamp.common.notify.obj.Contact;
import com.iflytek.uoamp.common.notify.obj.Notification;
import com.iflytek.uoamp.common.notify.plugins.AbstractPlugin;
import com.iflytek.uoamp.common.notify.util.Configurator;
import com.iflytek.uoamp.common.notify.util.LogInfo;
import com.iflytek.uoamp.common.notify.util.LogbackInstance;
import com.iflytek.uoamp.common.notify.util.NotifyUtils;
import com.iflytek.uoamp.common.notify.util.SerializationInstance;
import com.iflytek.uoamp.notify.core.protocol.DumpInfo;
import com.iflytek.uoamp.notify.core.protocol.PluginNode;

public class DumpTask extends TimerTask {
	
	private int maxRetryCounts = 0;
	private String parentFolder;
	private LogInfo logInfo = new LogInfo();
	private static final Logger logger = LogbackInstance.getInstance().getLogger(DumpTask.class);
	private static final String SEPARATOR = "######";
	
	public DumpTask() {
		maxRetryCounts = Configurator.getInstance().getPropertyByKey(ConfigName.MAX_RETRY_COUNTS, 0);
		parentFolder = Configurator.getInstance().getPropertyByKey(ConfigName.DUMP_FOLDER, System.getProperty("user.dir"));
		String separator = System.getProperty("file.separator");
		if(!parentFolder.endsWith(separator)) {
		    parentFolder += separator;
		}
	}

	@Override
	public void run() {
		try {
            scanFile();
        } catch (NotifyException e) {
            logInfo.addError(e.getMessage());
        } finally {
            logInfo.write();
        }
	}
	
    public static void writeToFile(DumpInfo info) {
        String content = info.getContent();
        if (!StringUtils.isBlank(content)) {
            String xml = SerializationInstance.sharedInstance().toXml(info, ConstField.UTF8, true);
            logger.info(xml);
        }
    }
    
    public static void dumpAll(Notification notification) throws NotifyException{
        List<?> pluginNodes = notification.getPluginNodes();
        
        if(pluginNodes == null || pluginNodes.isEmpty()) {
            return ;
        }
        
        for(Object o : pluginNodes) {
            PluginNode pluginNode = (PluginNode)o;
            AbstractPlugin plugin = NotifyUtils.getPlugin(pluginNode.getPluginType());
            
            if(plugin == null) {
                continue;
            }
            
            List<?> contents = pluginNode.getContent();
            contents = contents == null ? notification.getContent() : contents;
            List<Contact> contacts = pluginNode.getContacts();
            contacts = contacts == null ? notification.getContacts() : contacts;
            
            if(contents == null || contents.isEmpty() || 
                    contacts == null || contacts.isEmpty()) {
                continue;
            }
            
            String text = getPrettyText(notification, plugin, contents);
            DumpInfo dumpInfo = new DumpInfo(contacts, text, pluginNode.getPluginType());
            DumpTask.writeToFile(dumpInfo);
        }
    }
		
	private void scanFile() throws NotifyException {
		File root = new File(parentFolder);
		File[] files = root.listFiles(new NotificationFileFilter(System.currentTimeMillis()));
		
		if(files == null) {
		    return ;
		}

		for(File file : files) {
			resendFile(file);
		}
	}
	
	private void resendFile(File file) throws NotifyException{
	    List<DumpInfo> dumpInfos = getInfos(file);
        if(dumpInfos == null || dumpInfos.isEmpty()) {
            return ;
        }
        
	    for(DumpInfo dumpInfo : dumpInfos) {
	        int retryCounts = dumpInfo.getRetryCounts();
            if(retryCounts < maxRetryCounts) {
                dumpInfo.setRetryCounts(retryCounts + 1);
                if(!resendNotification(dumpInfo)) {
                    writeToFile(dumpInfo);
                }
            } else {
                saveFailedInfo(dumpInfo);
            }
	    }
	    file.delete();     //此时当前文件中的所有信息已经全部被处理,该文件不再包含有用信息
	}
	
	private List<DumpInfo> getInfos(File file) throws NotifyException{
	    DumpInfo dumpInfo = null;
	    List<DumpInfo> infoList = new ArrayList<DumpInfo>();
        try {
            String text = FileUtils.readFileToString(file, ConstField.UTF8);
            if(StringUtils.isBlank(text)) {
                return infoList;
            }
            
            String[] infos = text.split(SEPARATOR);
            for(String info : infos) {
                dumpInfo = SerializationInstance.sharedInstance().fromXml(DumpInfo.class, info);
                infoList.add(dumpInfo);
            }
        } catch (Exception e) {
            throw new NotifyException(MessageFormat.format(
                    ConstField.READINFOFAILED, e.getMessage()));
        }
        
        return infoList;
	}
	
	private boolean saveFailedInfo(DumpInfo dumpInfo) {
		String fileName = parentFolder + "errorInfo_" + new SimpleDateFormat("yyyy-MM-dd").format(System.currentTimeMillis());
		File file = new File(fileName);
		try {
			if(!file.exists()) {
				file.createNewFile();
			}
			
			String contacts = NotifyUtils.getContactList(dumpInfo.getContacts());
			logInfo.addInfo(MessageFormat.format(ConstField.ADDCONTACTTOFAILEDFILE,
			        contacts, file.getAbsolutePath()));
			String content = SerializationInstance.sharedInstance().toXml(dumpInfo, ConstField.UTF8, true);
			FileUtils.write(file, content, ConstField.UTF8, true);
		} catch (Exception e) {
		    logInfo.addError(MessageFormat.format(ConstField.NOAVAILABLEFAILEDINFO,
			        file.getAbsolutePath(), e.getMessage()));
			return false;
		}
		
		return true;
	}
	
	private boolean resendNotification(DumpInfo dumpInfo) {
	    String contactList = NotifyUtils.getContactList(dumpInfo.getContacts());
	    
	    if(!StringUtils.isBlank(dumpInfo.getContent())) {
	        logInfo.addInfo(MessageFormat.format(ConstField.RESENDINGCONTENT, 
	                dumpInfo.getRetryCounts(), dumpInfo.getPluginType(), 
	                contactList));
	        if(resendContent(dumpInfo)) {
	            return true;
	        }
	    }
	    
	    return false;
	}
	
	private boolean resendContent(DumpInfo dumpInfo) {
        String content = dumpInfo.getContent();
	    List<Contact> contacts = dumpInfo.getContacts();
	    
        try {
            AbstractPlugin plugin = NotifyUtils.getPlugin(dumpInfo.getPluginType());
            plugin.setLogInfo(logInfo);
            return plugin.sendContent(content, contacts);
        } catch (NotifyException e) {
            logInfo.addError(e.getMessage());
        }
        
        return false;
	}
	
	private static String getPrettyText(Notification notification, 
            AbstractPlugin plugin, List<?> contents) throws NotifyException{
        Type type = Type.getType(notification.getType());
        plugin.setNotification(notification);
        if(type == Type.FULL_TEMPLATE || type == Type.ID_ONLY) {
            plugin.setUseTemplate(true);
        }
            
        return plugin.getFormatter().pretty(notification, contents);
    }
}
